package edu.szte.ovrt.datahandler.core;

import java.io.File;
import java.io.IOException;
import java.util.*;

@SuppressWarnings("unchecked")
public class IOMetaFactory {
	private static final String CLASSES_CONFIG = "extensions.classes.properties";
	private static final String PREFIX = "file.extension.";
	private static final IOMetaFactory s_instance = new IOMetaFactory();
	private static final Map<String, Class<? extends IOFactory>> s_factoryMap = new HashMap<String, Class<? extends IOFactory>>();
	static {
		final Properties extensions = new Properties();
		String extension = null;
		try {
			System.out.println("Loading file extensions.");
			extensions.load(IOMetaFactory.class.getResourceAsStream(CLASSES_CONFIG));
		} catch (final IOException e) {
			System.err.println("Failed to initialize extension factories, there must be a file under "
					+ IOMetaFactory.class.getPackage().getName() + " named " + CLASSES_CONFIG
					+ ". The file should contain properties in format of " + "\"" + PREFIX
					+ "ext=fully.qualified.factory.class.name\"" + ", where ext is the extension which the factory can handle.");
		}
		for (final String extensionSetting : Collections.list(((Enumeration<String>) extensions.propertyNames()))) {
			if (extensionSetting.startsWith(PREFIX)) {
				extension = extensionSetting.substring(PREFIX.length());
				final String factoryClassName = extensions.getProperty(extensionSetting);
				try {
					final Class<?> factoryClass = Class.forName(factoryClassName);
					if (IOFactory.class.isAssignableFrom(factoryClass)) {
						s_factoryMap.put(extension.toLowerCase(), (Class<? extends IOFactory>) factoryClass);
						System.out.println("Loaded factory for " + extension);
					} else {
						System.err.println("Invalid factory for " + extension);
					}
				} catch (final ClassNotFoundException e) {
					System.err.println("Factory class " + e.getMessage() + " cannot be found for extension: " + extension);
				}
			}
		}
	}

	public static IOMetaFactory getInstance() {
		return s_instance;
	}

	public IOFactory getIOFactory(final String fileName) {
		final String extension = getExtension(fileName);
		final Class<? extends IOFactory> factoryClass = s_factoryMap.get(extension.toLowerCase());
		IOFactory factory = null;
		if (factoryClass != null) {
			try {
				factory = factoryClass.newInstance();
				factory.setFileName(fileName);
			} catch (final InstantiationException e) {
				System.err.println("Wrong factory class (" + factoryClass + "), cannot instantiate: " + e);
			} catch (final IllegalAccessException e) {
				System.err.println("Wrong factory class (" + factoryClass + "), constructor inaccessible: " + e);
			}
		}
		return factory;
	}

	private static String getExtension(String fileName) {
		fileName = new File(fileName).getAbsolutePath();
		final int lastDot = fileName.lastIndexOf('.');
		final int lastPath = fileName.lastIndexOf(File.separatorChar);
		return lastPath < lastDot ? fileName.substring(lastDot + 1) : "";
	}
}
